/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dca.sistemascontrole.view.grafico;

import dca.sistemascontrole.domain.DataObject;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.TimeSeriesDataItem;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleInsets;

/**
 *
 * @author Rafael
 */
public class GraficoNivel extends JPanel {

    private XYPlot xyplot;
    private XYPlot xyplotTensao;
    private ChartPanel pnlChart;
    private TimeSeries timeSeriesTanqueSuperior;
    private TimeSeries timeSeriesTanqueInferior;
    private TimeSeries timeSeriesSetpoint;
    private TimeSeries timeSeriesErro;
    private TimeSeriesCollection timeSeriesCollection;
    private long maximunVisiblePeriod;
    private Lock lock = new ReentrantLock();

    public GraficoNivel() {
        this("", "", "", GraphicPanel.DEFAULT_MAXIMUN_VISIBLE_PERIOD);
    }

    public GraficoNivel(long maximunVisibleWindow) {
        this("", "", "", maximunVisibleWindow);
    }

    public GraficoNivel(String title, String timeAxisLabel, String valueAxisLabel, long maximunVisibleWindow) {
        this.maximunVisiblePeriod = maximunVisibleWindow;

        setLayout(new BorderLayout());
        timeSeriesTanqueSuperior = new TimeSeries("Tanque Superior");
        timeSeriesTanqueSuperior.removeAgedItems(true);
        timeSeriesTanqueInferior = new TimeSeries("Tanque Inferior");
        timeSeriesTanqueInferior.removeAgedItems(true);
        timeSeriesSetpoint = new TimeSeries("Setpoint");
        timeSeriesSetpoint.removeAgedItems(true);
        timeSeriesErro = new TimeSeries("Erro");
        timeSeriesErro.removeAgedItems(true);

        timeSeriesCollection = new TimeSeriesCollection();
        timeSeriesCollection.addSeries(timeSeriesTanqueSuperior);
        timeSeriesCollection.addSeries(timeSeriesTanqueInferior);
        timeSeriesCollection.addSeries(timeSeriesSetpoint);
        timeSeriesCollection.addSeries(timeSeriesErro);

        JFreeChart jfreechart = createChart(timeSeriesCollection, title, timeAxisLabel, "(cm)");
        pnlChart = new ChartPanel(jfreechart);
        pnlChart.setBackground(new Color(247, 247, 247));
        pnlChart.setVisible(true);
        add(pnlChart, BorderLayout.CENTER);

        pnlChart.addChartMouseListener(new ChartMouseListener() {
            public void chartMouseClicked(ChartMouseEvent event) {
            }

            public void chartMouseMoved(ChartMouseEvent event) {
                Point2D p = pnlChart.translateScreenToJava2D(event.getTrigger().getPoint());
                Rectangle2D plotArea = pnlChart.getScreenDataArea();
                double chartX = xyplot.getDomainAxis().java2DToValue(p.getX(), plotArea, xyplot.getDomainAxisEdge());

                Date date = new Date((long) chartX);

                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);

                System.out.println("Tempo = " + (calendar.get(Calendar.HOUR) + 12) % 24 + ":"
                        + calendar.get(Calendar.MINUTE) + ":"
                        + calendar.get(Calendar.SECOND) + ":"
                        + calendar.get(Calendar.MILLISECOND));

                xyplot.setDomainCrosshairValue(chartX);
                xyplotTensao.setDomainCrosshairValue(chartX);
                
//                FixedMillisecond f0 = new FixedMillisecond(date.getTime() - 50);
//                FixedMillisecond f1 = new FixedMillisecond(date.getTime() + 50);
//                try {
//                    TimeSeries createCopy = timeSeriesTanqueInferior.createCopy(f0, f1);
//                    System.out.println("createCopy = " + createCopy);
//                    if (createCopy != null && !createCopy.isEmpty()) {
//                        System.out.println("size = " + createCopy.getItemCount());
//                        System.out.println("Valor = " + createCopy.getValue(0));
//                    }
//                } catch (CloneNotSupportedException ex) {
//                    Logger.getLogger(GraficoNivel.class.getName()).log(Level.SEVERE, null, ex);
//                }
            }
        });
    }

    public void addValue(double valueSuperior, double valueInferior, double setPoint, double erro, FixedMillisecond time) {
        try {
            lock.lock();
            TimeSeriesDataItem seriesDataItemSuperior = new TimeSeriesDataItem(time, valueSuperior);
            TimeSeriesDataItem seriesDataItemInferior = new TimeSeriesDataItem(time, valueInferior);
            TimeSeriesDataItem seriesDataItemSetpoint = new TimeSeriesDataItem(time, setPoint);
            TimeSeriesDataItem seriesDataItemErro = new TimeSeriesDataItem(time, erro);

            timeSeriesTanqueSuperior.addOrUpdate(seriesDataItemSuperior);
            timeSeriesTanqueInferior.addOrUpdate(seriesDataItemInferior);
            timeSeriesSetpoint.addOrUpdate(seriesDataItemSetpoint);
            timeSeriesErro.addOrUpdate(seriesDataItemErro);
            pnlChart.revalidate();
            pnlChart.repaint();
        } finally {
            lock.unlock();
        }
    }

    public void clear() {
        timeSeriesTanqueInferior.clear();
        timeSeriesTanqueSuperior.clear();
        timeSeriesSetpoint.clear();
        timeSeriesErro.clear();
    }

    protected JFreeChart createChart(XYDataset xydataset, String title, String timeAxisLabel, String valueAxisLabel) {
        JFreeChart jfreechart = ChartFactory.createTimeSeriesChart(title, timeAxisLabel, valueAxisLabel, xydataset, true, true, false);
        xyplot = (XYPlot) jfreechart.getPlot();

        xyplot.setBackgroundPaint(Color.white);
        xyplot.setDomainGridlinePaint(Color.gray);
        xyplot.setRangeGridlinePaint(Color.gray);
        xyplot.setOutlineVisible(false);
        xyplot.setInsets(new RectangleInsets(0, 5, 5, 0));

        xyplot.setDomainPannable(true);
        xyplot.setRangePannable(false);
        xyplot.setDomainCrosshairVisible(true);
        xyplot.setRangeCrosshairVisible(true);

        XYItemRenderer renderer = xyplot.getRenderer();
        renderer.setSeriesPaint(0, Color.RED);
        renderer.setSeriesPaint(1, Color.BLUE);
        renderer.setSeriesPaint(2, Color.GREEN);
        renderer.setSeriesPaint(3, Color.BLACK);

        NumberAxis range = (NumberAxis) xyplot.getRangeAxis();
        range.setRange(-5.00, 30.00);

        ValueAxis valueaxis = xyplot.getDomainAxis();
        valueaxis.setAutoRange(true);
        valueaxis.setFixedAutoRange(GraphicPanel.DEFAULT_MAXIMUN_VISIBLE_PERIOD);

        jfreechart.setBackgroundPaint(Color.WHITE);

        return jfreechart;
    }

    public long getMaximunVisiblePeriod() {
        return maximunVisiblePeriod;
    }

    public void setMaximunVisiblePeriod(long maximunVisiblePeriod) {
        this.maximunVisiblePeriod = maximunVisiblePeriod;
    }

    public void setValues(List<DataObject> nivelTanqueInferior, List<DataObject> nivelTanqueSuperior, List<DataObject> erro, List<DataObject> setpoint) {
        for (DataObject dataObject : nivelTanqueSuperior) {
            timeSeriesTanqueSuperior.addOrUpdate(dataObject.getMillisecond(), dataObject.getValue());
        }

        for (DataObject dataObject : nivelTanqueInferior) {
            timeSeriesTanqueInferior.addOrUpdate(dataObject.getMillisecond(), dataObject.getValue());
        }

        for (DataObject dataObject : setpoint) {
            timeSeriesSetpoint.addOrUpdate(dataObject.getMillisecond(), dataObject.getValue());
        }

        for (DataObject dataObject : erro) {
            timeSeriesErro.addOrUpdate(dataObject.getMillisecond(), dataObject.getValue());
        }
    }

    public void exibirNivelTanqueSuperior(boolean exibir) {
        if (exibir) {
            List series = timeSeriesCollection.getSeries();
            if (!series.contains(timeSeriesTanqueSuperior)) {
                timeSeriesCollection.addSeries(timeSeriesTanqueSuperior);
            }
        } else {
            timeSeriesCollection.removeSeries(timeSeriesTanqueSuperior);
        }
    }

    public void exibirNivelTanqueInferior(boolean exibir) {
        if (exibir) {
            List series = timeSeriesCollection.getSeries();
            if (!series.contains(timeSeriesTanqueInferior)) {
                timeSeriesCollection.addSeries(timeSeriesTanqueInferior);
            }
        } else {
            timeSeriesCollection.removeSeries(timeSeriesTanqueInferior);
        }
    }

    public void exibirSetpoint(boolean exibir) {
        if (exibir) {
            List series = timeSeriesCollection.getSeries();
            if (!series.contains(timeSeriesSetpoint)) {
                timeSeriesCollection.addSeries(timeSeriesSetpoint);
            }
        } else {
            timeSeriesCollection.removeSeries(timeSeriesSetpoint);
        }
    }

    public void exibirErro(boolean exibir) {
        if (exibir) {
            List series = timeSeriesCollection.getSeries();
            if (!series.contains(timeSeriesErro)) {
                timeSeriesCollection.addSeries(timeSeriesErro);
            }
        } else {
            timeSeriesCollection.removeSeries(timeSeriesErro);
        }
    }

    public XYPlot getXyplot() {
        return xyplot;
    }

    public void setXyplotTensao(XYPlot xyplotTensao) {
        this.xyplotTensao = xyplotTensao;
    }
}
